/**
 *    Copyright (C) 2008  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_TOOLS_TYPES_STATIC_BITMAP_HPP
#define	_CUBEFS_CORE_TOOLS_TYPES_STATIC_BITMAP_HPP

#include <cubefs/core/tools/bitmap.hpp>
#include <cubefs/core/tools/types/typelist.hpp>

namespace cubefs        {
namespace tools         {

using cubefs::TypeList;

template <BigInt V0, BigInt V1, BigInt V2, BigInt V3>
struct Bitmap {
    typedef Bitmap<V0, V1, V2, V3> BitmapType;

    static const BigInt v0 = V0;
    static const BigInt v1 = V1;
    static const BigInt v2 = V2;
    static const BigInt v3 = V3;
};

typedef Bitmap<0,0,0,0>                 ZeroBitmap;
typedef Bitmap<-1ll, -1ll, -1ll, -1ll>  OneBitmap;


template <typename B1, typename B2>
struct And: public Bitmap<B1::v0 & B2::v0, B1::v1 & B2::v1, B1::v2 & B2::v2, B1::v3 & B2::v3> {};

template <typename B1, typename B2>
struct Or: public  Bitmap<B1::v0 | B2::v0, B1::v1 | B2::v1, B1::v2 | B2::v2, B1::v3 | B2::v3> {};

template <typename B1, typename B2>
struct Xor: public Bitmap<B1::v0 ^ B2::v0, B1::v1 ^ B2::v1, B1::v2 ^ B2::v2, B1::v3 ^ B2::v3> {};

template <typename B1>
struct Not: public Bitmap<~B1::v0, ~B1::v1, ~B1::v2, ~B1::v3> {};

template <Int Idx, Int Count, BigInt Bits, Int Selector, bool Dbl> class MakeBitmapTool;

template <Int Idx, Int Count, BigInt Bits> struct BitmapValuePier {
    typedef MakeMaskTool<BigInt, Count - (64 - Idx), 0> Mask;

    static const BigInt v0 = Bits << Idx;
    static const BigInt v1 = (Bits >> (64 - Idx)) & Mask::Value;
};

template <Int Idx, Int Count, BigInt Bits> struct SingleBitmapValue {
    typedef MakeMaskTool<BigInt, Count, Idx> Mask;
    static const BigInt v0 = (Bits << Idx) & Mask::Value;
};

template <Int Idx, Int Count, BigInt Bits>
class MakeBitmapTool<Idx, Count, Bits, 0, true> {
    typedef BitmapValuePier<Idx, Count, Bits> Pier;
public:
    typedef Bitmap<Pier::v0, Pier::v1, 0, 0> Result;
};

template <Int Idx, Int Count, BigInt Bits>
class MakeBitmapTool<Idx, Count, Bits, 1, true> {
    typedef BitmapValuePier<Idx, Count, Bits> Pier;
public:
    typedef Bitmap<0, Pier::v0, Pier::v1, 0> Result;
};


template <Int Idx, Int Count, BigInt Bits>
class MakeBitmapTool<Idx, Count, Bits, 2, true> {
    typedef BitmapValuePier<Idx, Count, Bits> Pier;
public:
    typedef Bitmap<0, 0, Pier::v0, Pier::v1> Result;
};

template <Int Idx, Int Count, BigInt Bits>
class MakeBitmapTool<Idx, Count, Bits, 0, false> {
    typedef SingleBitmapValue<Idx, Count, Bits> V;
public:
    typedef Bitmap<V::v0, 0, 0, 0> Result;
};

template <Int Idx, Int Count, BigInt Bits>
class MakeBitmapTool<Idx, Count, Bits, 1, false> {
    typedef SingleBitmapValue<Idx, Count, Bits> V;
public:
    typedef Bitmap<0, V::v0, 0, 0> Result;
};

template <Int Idx, Int Count, BigInt Bits>
class MakeBitmapTool<Idx, Count, Bits, 2, false> {
    typedef SingleBitmapValue<Idx, Count, Bits> V;
public:
    typedef Bitmap<0, 0, V::v0, 0> Result;
};


template <Int Idx, Int Count, BigInt Bits>
class MakeBitmapTool<Idx, Count, Bits, 3, false> {
    typedef SingleBitmapValue<Idx, Count, Bits> V;
public:
    typedef Bitmap<0, 0, 0, V::v0> Result;
};

template <Int Idx = 0, Int Count = 0, BigInt Bits = 0>
struct MakeBitmap: public MakeBitmapTool<Idx % 64, Count, Bits, Idx / 64, ((Idx % 64) + Count > 64)>::Result {};

template <typename Field>
struct MakeBitmapFromField: public MakeBitmapTool<Field::Idx % 64, Field::Count, Field::Bits, Field::Idx / 64, ((Field::Idx % 64) + Field::Count > 64)>::Result {};


template <typename B1, typename B2, Int Idx, Int Count>
class SetBitsTool {
public:
    static const BigInt Bits = MakeMaskTool<BigInt, Count, 0>::Value;

    typedef typename MakeBitmap<Idx, Count, Bits>::Result Mask;
public:
    typedef Or<And<B1, Not<Mask> >, And<B2, Mask> > Result;
};

template <typename B1, typename B2, Int Idx, Int Count>
struct SetBits: public SetBitsTool<B1, B2, Idx, Count>::Result {};



template <typename B, Int Idx, Int Count, Int Selector, bool Dbl> class GetBitsTool;

template <BigInt v0, Int Idx, Int Count>
class SingleValueGetBits {
    typedef MakeMaskTool<BigInt, Count, 0> Mask;
public:
    static const BigInt Value = (v0 >> Idx) & Mask::Value;
};

template <BigInt v0, BigInt v1, Int Idx, Int Count>
class DoubleValueGetBits {
    typedef MakeMaskTool<BigInt, 64 - Idx, 0>           Mask0;
    typedef MakeMaskTool<BigInt, Count - (64 - Idx), 0> Mask1;
public:
    static const BigInt Value = (v0 >> Idx) & Mask0::Value + ((v1 & Mask1::Value) << (64 - Idx));
};


template <typename B, Int Idx, Int Count>
class GetBitsTool<B, Idx, Count, 0, false> {
public:
    static const BigInt Value = SingleValueGetBits<B::v0, Idx, Count>::Value;
};

template <typename B, Int Idx, Int Count>
class GetBitsTool<B, Idx, Count, 1, false> {
public:
    static const BigInt Value = SingleValueGetBits<B::v1, Idx, Count>::Value;
};

template <typename B, Int Idx, Int Count>
class GetBitsTool<B, Idx, Count, 2, false> {
public:
    static const BigInt Value = SingleValueGetBits<B::v2, Idx, Count>::Value;
};

template <typename B, Int Idx, Int Count>
class GetBitsTool<B, Idx, Count, 3, false> {
public:
    static const BigInt Value = SingleValueGetBits<B::v3, Idx, Count>::Value;
};


template <typename B, Int Idx, Int Count>
class GetBitsTool<B, Idx, Count, 0, true> {
public:
    static const BigInt Value = DoubleValueGetBits<B::v0, B::v1, Idx, Count>::Value;
};

template <typename B, Int Idx, Int Count>
class GetBitsTool<B, Idx, Count, 1, true> {
public:
    static const BigInt Value = DoubleValueGetBits<B::v1, B::v2, Idx, Count>::Value;
};

template <typename B, Int Idx, Int Count>
class GetBitsTool<B, Idx, Count, 2, true> {
public:
    static const BigInt Value = DoubleValueGetBits<B::v2, B::v3, Idx, Count>::Value;
};


template <typename B, Int Idx, Int Count>
struct GetBits: public GetBitsTool<B, Idx % 64, Count, Idx / 64, ((Idx % 64) + Count > 64)> {};


template <typename B, typename Field>
struct GetValue: public GetBits<B, Field::Offset, Field::Size> {};

template <Int Offset_, Int Size_>
struct BitmapField {
    static const BigInt Offset  = Offset_;
    static const BigInt Size    = Size_;
};


template <Int Offset, Int Size, BigInt Value_>
struct BitmapItem: public BitmapField<Offset, Size> {
    static const BigInt Value   = Value_;
};


template <typename List> class BitmapFromListTool;

template <typename Head, typename Tail>
class BitmapFromListTool<TypeList<Head, Tail> > {
    typedef MakeBitmap<Head::Offset, Head::Size, Head::Value> B;
public:
    typedef SetBits<BitmapFromListTool<Tail>, B, Head::Offset, Head::Size> Result;
};

template <typename Head>
class BitmapFromListTool<TypeList<Head, NullType> > {
    typedef MakeBitmap<Head::Offset, Head::Size, Head::Value> B;
public:
    typedef B Result;
};


template <typename List>
struct BitmapFromList: public BitmapFromListTool<List>::Result {};

} //tools
} //cubefs


#endif	/* _CUBEFS_CORE_TOOLS_TYPES_STATIC_BITMAP_HPP */

